package com.eternal.rxble;

import android.Manifest;
import android.app.Application;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothManager;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanResult;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Build;
import androidx.annotation.RequiresApi;
import androidx.annotation.RequiresPermission;

import com.eternal.rxble.exception.BlueException;
import com.eternal.rxble.exception.NotCloseScanException;

import java.util.List;

import io.reactivex.Observable;
import io.reactivex.ObservableEmitter;
import io.reactivex.ObservableOnSubscribe;

/**
 * Created by Administrator
 * On 2020/4/26
 * Description:
 * @author Administrator
 */
public class BleManager {
    private BluetoothManager manager;
    private BluetoothAdapter adapter;
    private Context context;
    private BluetoothLeScanner scanner;
    private BluetoothGatt gatt;

    public void init(Application app){
        context=app;
        if(isSupportBle()){
            manager= (BluetoothManager) app.getSystemService(Context.BLUETOOTH_SERVICE);
        }
        adapter=BluetoothAdapter.getDefaultAdapter();
    }

    @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
    public boolean isEnabled(){
        return adapter.enable();
    }
    @RequiresPermission(allOf = {Manifest.permission.BLUETOOTH, Manifest.permission.BLUETOOTH_ADMIN})
    public void enable(){
        if(!adapter.isEnabled()){
            adapter.enable();
        }
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public Observable<List<ScanResult>> stopScan(){
        if(scanner!=null){
            return Observable.create(new ObservableOnSubscribe<List<ScanResult>>() {
                @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
                @Override
                public void subscribe(final ObservableEmitter<List<ScanResult>> emitter) throws Exception {
                    scanner.stopScan(new ScanCallback() {
                        @Override
                        public void onBatchScanResults(List<ScanResult> results) {
                            emitter.onNext(results);
                            scanner=null;
                        }

                        @Override
                        public void onScanFailed(int errorCode) {
                            emitter.onError(new BlueException(errorCode, "stop scan failed"));
                        }
                    });
                }
            });
        }
        return Observable.empty();
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public Observable<List<ScanResult>> scan(){
        return Observable.create(new ObservableOnSubscribe<List<ScanResult>>() {
            @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
            @Override
            public void subscribe(final ObservableEmitter<List<ScanResult>> emitter) throws Exception {
                if(scanner!=null){
                    emitter.onError(new NotCloseScanException());
                }else{
                    scanner=adapter.getBluetoothLeScanner();
                    scanner.startScan(new ScanCallback() {
                        @Override
                        public void onBatchScanResults(List<ScanResult> results) {
                            emitter.onNext(results);
                        }
                    });
                }

            }
        });
    }

    public BluetoothDevice getDeviceByMac(String mac){
        return adapter.getRemoteDevice(mac);
    }

    public Observable<BluetoothGatt> connect(final BluetoothDevice device){
        return Observable.create(new ObservableOnSubscribe<BluetoothGatt>() {
            @Override
            public void subscribe(ObservableEmitter<BluetoothGatt> emitter) throws Exception {
                gatt=device.connectGatt(context, false, new BluetoothGattCallback() {
                    @Override
                    public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {

                    }
                });
                emitter.onNext(gatt);
            }
        });
    }

    /**
     * is support ble?
     *
     * @return
     */
    public boolean isSupportBle() {
        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2
                && context.getApplicationContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE);
    }
}
